#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
API网关服务
为微信小程序提供HTTPS API接口，支持多GPU服务器负载均衡
"""

from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
import requests
import os
import json
import time
from urllib.parse import urljoin
import logging
from config import config

# 导入多GPU服务器管理模块
from backend_manager import backend_manager
from request_stats import request_stats
from webhook_routes import register_webhook_routes
from simple_task_mapping import simple_task_mapping

# 导入微信支付相关模块
from wechat_pay_utils import WeChatPayAPI, WeChatPayUtils
from order_manager import OrderManager
from wechat_pay_config import WeChatPayConfig
from wechat_auth import WeChatAuth

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)

# 配置CORS，明确允许的域名和请求头
CORS(
    app,
    origins=[
        "https://www.gongjuxiang.work",
        "https://gongjuxiang.work",
        "http://localhost:3000",  # 开发环境
        "http://127.0.0.1:3000",  # 开发环境
    ],
    methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["Content-Type", "Authorization", "X-Session-ID"],
    supports_credentials=True,
)

# 注册webhook路由
register_webhook_routes(app)

# ============================================
# 请求统计功能
# ============================================

@app.before_request
def track_request_start():
    """记录请求开始"""
    request.start_time = time.time()
    request_stats.on_request_start()


@app.after_request
def track_request_end(response):
    """记录请求结束"""
    if hasattr(request, 'start_time'):
        response_time = time.time() - request.start_time
        success = 200 <= response.status_code < 400
        request_stats.on_request_end(response_time, success)
    return response


# 从配置文件获取后端API服务器配置
BACKEND_TIMEOUT = config.get_timeout()

# 支持的API端点
SUPPORTED_ENDPOINTS = config.get_endpoints()

# 初始化微信支付相关组件
pay_api = WeChatPayAPI()
order_manager = OrderManager()
wechat_auth = WeChatAuth()


@app.route("/api/v1/upload/presigned-url", methods=["POST"])
def generate_presigned_url():
    """
    生成COS预签名上传URL
    允许前端直接上传到COS，避免双重上传
    """
    try:
        # 获取参数
        data = request.get_json()
        user_id = data.get("user_id", "anonymous")
        file_type = data.get("file_type", "image/jpeg")
        file_size = data.get("file_size", 0)
        filename = data.get("filename", "image.jpg")

        # 验证文件大小（限制100MB）
        if file_size > 100 * 1024 * 1024:
            return jsonify({"success": False, "error": "文件大小不能超过100MB"}), 400

        # 验证文件类型
        allowed_types = ["image/jpeg", "image/jpg", "image/png", "image/webp"]
        if file_type not in allowed_types:
            return (
                jsonify(
                    {
                        "success": False,
                        "error": f'不支持的文件类型，仅支持: {", ".join(allowed_types)}',
                    }
                ),
                400,
            )

        # 生成文件键
        import uuid

        file_extension = filename.split(".")[-1] if "." in filename else "jpg"
        cos_key = f"uploads/{user_id}/{uuid.uuid4().hex}.{file_extension}"

        # 初始化COS客户端
        from qcloud_cos import CosConfig, CosS3Client

        cos_config = CosConfig(
            Region=os.getenv("COS_REGION", "ap-beijing"),
            SecretId=os.getenv("COS_SECRET_ID"),
            SecretKey=os.getenv("COS_SECRET_KEY"),
            Scheme="https",
        )
        cos_client = CosS3Client(cos_config)
        bucket_name = os.getenv("COS_BUCKET_NAME", "photoenhancei-bj-1259206939")

        # 生成预签名URL（有效期1小时）
        presigned_url = cos_client.get_presigned_url(
            Method="PUT", Bucket=bucket_name, Key=cos_key, Expired=3600
        )

        # 生成下载URL
        download_url = f"https://{bucket_name}.cos.{os.getenv('COS_REGION', 'ap-beijing')}.myqcloud.com/{cos_key}"

        logger.info(f"生成预签名URL成功: {cos_key}, 用户: {user_id}")

        return (
            jsonify(
                {
                    "success": True,
                    "presigned_url": presigned_url,
                    "cos_key": cos_key,  # 统一使用cos_key
                    "download_url": download_url,
                }
            ),
            200,
        )

    except Exception as e:
        logger.error(f"生成预签名URL失败: {e}")
        return jsonify({"success": False, "error": "生成上传链接失败"}), 500


def _process_single_image_internal(
    cos_key, quality_level="high", tile_size=None, session_id=None
):
    """
    单图处理核心逻辑（内部函数）- 优雅架构版
    
    职责分离：
    - backend_manager：负责服务器选择和故障转移
    - 本函数：只负责调用和处理结果
    
    参数:
        cos_key: COS中的文件路径（对象键）
        quality_level: 处理质量 (high/medium/low)
        tile_size: 可选，分块大小
        session_id: 可选，会话ID
    
    返回:
        成功: {'success': True, 'task_id': '...', 'cdn_url': '...', ...}
        失败: {'success': False, 'error': '...', 'detail': '...'}
    """
    try:
        logger.info(f"[单图处理] cos_key: {cos_key}")
        
        # 准备请求数据
        data = {"cos_key": cos_key, "quality_level": quality_level}
        if tile_size:
            data["tile_size"] = tile_size
        if session_id:
            data["session_id"] = session_id
        
        # ✅ 智能重试：最多尝试所有健康服务器
        max_attempts = len([s for s in backend_manager.servers.values() if s.is_healthy])
        if max_attempts == 0:
            logger.error("[单图处理] 没有可用的GPU服务器")
            return {
                "success": False,
                "error": "服务暂时不可用，请稍后重试",
                "detail": "没有可用的GPU服务器",
            }
        
        logger.info(f"[单图处理] 可用GPU服务器: {max_attempts}台")
        
        # ✅ 尝试所有健康服务器（由 backend_manager 负责选择）
        for attempt in range(1, max_attempts + 1):
            server = backend_manager.get_next_server()
            
            if not server:
                logger.warning(f"[单图处理] 第 {attempt}/{max_attempts} 次尝试：没有可用服务器")
                continue
            
            try:
                backend_url = server.url
                full_url = urljoin(backend_url, "/api/v1/enhance-by-cos-key")
                
                logger.info(f"[单图处理] 第 {attempt}/{max_attempts} 次尝试：{server.server_id} ({backend_url})")
                
                # 尝试请求
                response = requests.post(full_url, json=data, timeout=300)
                logger.info(f"[单图处理] 服务器 {server.server_id} 响应: {response.status_code}")
                
                # 解析结果
                backend_result = response.json()
                
                if response.status_code == 200 and backend_result.get("success"):
                    # ✅ 成功
                    logger.info(f"[单图处理] ✅ 成功！使用服务器: {server.server_id}")
                    return {
                        "success": True,
                        "task_id": backend_result.get("task_id"),
                        "cdn_url": backend_result.get("cdn_url"),
                        "processing_time": backend_result.get("processing_time", 0),
                        "download_time": 0,
                        "upload_time": 0,
                        "total_time": backend_result.get("processing_time", 0),
                    }
                else:
                    # 服务器返回了业务错误（如图片格式错误）
                    # 这不是服务器故障，直接返回错误，不尝试其他服务器
                    logger.warning(f"[单图处理] 业务错误: {backend_result.get('error')}")
                    return {
                        "success": False,
                        "error": backend_result.get("error", "处理失败"),
                        "detail": backend_result.get("detail", ""),
                    }
            
            except requests.exceptions.RequestException as e:
                # ❌ 连接失败（服务器故障）
                logger.warning(f"[单图处理] 服务器 {server.server_id} 故障: {e}")
                
                # ✅ 立即标记服务器失败（加快健康检查响应）
                backend_manager.mark_server_failed(server.server_id)
                
                if attempt < max_attempts:
                    logger.info(f"[单图处理] 🔄 故障转移，尝试下一个服务器...")
                    continue  # 尝试下一个服务器
                else:
                    # 最后一次尝试也失败了
                    logger.error(f"[单图处理] ❌ 所有服务器都失败")
                    break
        
        # 所有服务器都失败了
        return {
            "success": False,
            "error": "所有GPU服务器都不可用",
            "detail": f"尝试了 {max_attempts} 台服务器，全部失败",
        }
    
    except Exception as e:
        logger.error(f"[单图处理] 处理失败: {e}", exc_info=True)
        return {"success": False, "error": "图片处理失败", "detail": str(e)}
@app.route("/api/v1/single-process-uploaded-image", methods=["POST"])
def process_uploaded_image():
    """
    处理已上传图片API - 处理存储在COS中的图片

    前端工作流:
    1. 前端调用 /api/v1/upload/presigned-url 获取上传URL
    2. 前端直接上传图片到COS，获得file_key
    3. 前端调用此接口，传递file_key
    4. 后端从COS下载 → GPU处理 → 上传结果到COS → 返回CDN URL

    请求体:
    {
        "cos_key": "uploads/user_xxx/xxx.jpg",  // COS中的文件路径
        "quality_level": "high"  // 可选，处理质量
    }
    """
    try:
        logger.info("收到图片增强请求（通过file_key）")

        # 获取JSON数据
        if request.is_json:
            request_data = request.get_json()
        else:
            request_data = request.form.to_dict()

        # 获取cos_key
        cos_key = request_data.get("cos_key")
        if not cos_key:
            return jsonify({"error": "缺少cos_key参数"}), 400

        # 获取可选参数
        quality_level = request_data.get("quality_level", "high")
        tile_size = request_data.get("tile_size")
        session_id = request.headers.get("X-Session-ID") or request_data.get(
            "session_id"
        )

        # 调用核心处理逻辑
        result = _process_single_image_internal(
            cos_key, quality_level, tile_size, session_id
        )

        # 返回结果
        if result.get("success"):
            return jsonify(result), 200
        else:
            return jsonify(result), 500

    except Exception as e:
        logger.error(f"图片增强失败: {e}", exc_info=True)
        return (
            jsonify({"success": False, "error": "图片增强失败", "detail": str(e)}),
            500,
        )


@app.route("/api/v1/batch-process-uploaded-image", methods=["POST"])
def batch_process_uploaded_image():
    """
    批量处理已上传图片API（并发+流式响应版）

    特点：
    - 并发处理：充分利用GPU集群资源
    - 按提交顺序返回：保证结果有序
    - 动态并发数：根据健康GPU数量自动调整
    - 流式响应：处理一张返回一张
    - 无数量限制：支持任意数量图片

    请求体:
    {
        "images": [
            {"cos_key": "uploads/user1/img1.jpg", "quality_level": "high"},
            {"cos_key": "uploads/user1/img2.jpg", "quality_level": "medium"}
        ]
    }

    响应格式（JSON Lines - 每行一个JSON，按提交顺序）:
    {"index": 0, "cos_key": "...", "success": true, "cdn_url": "...", "processing_time": 8.5}
    {"index": 1, "cos_key": "...", "success": false, "error": "文件不存在"}
    {"summary": {"total": 2, "completed": 2, "failed": 0, "total_time": 15.3, "concurrency": 3}}
    """
    from flask import Response
    import time
    from concurrent.futures import ThreadPoolExecutor, as_completed
    import threading

    # 在请求上下文中获取数据
    data = request.get_json()
    images = data.get("images", [])

    def generate():
        try:

            if not images:
                yield json.dumps(
                    {"success": False, "error": "images参数为空或格式错误"},
                    ensure_ascii=False,
                ) + "\n"
                return

            # 获取健康GPU数量，动态设置并发数
            healthy_server_urls = backend_manager.get_server_urls()
            concurrency = max(1, len(healthy_server_urls))
            
            logger.info(f"[批处理] 开始处理，共 {len(images)} 张图片，并发数: {concurrency}（健康GPU: {len(healthy_server_urls)}）")

            completed = 0
            failed = 0
            start_time = time.time()
            
            # ✅ 改为按完成顺序返回（无需缓存，提升用户体验）
            # results_cache = {}  # 不再需要
            # cache_lock = threading.Lock()
            # next_index_to_yield = 0

            # 处理单张图片的工作函数
            def process_one_image(index, img):
                cos_key = img.get("cos_key")
                quality_level = img.get("quality_level", "high")
                tile_size = img.get("tile_size")

                if not cos_key:
                    return {
                        "index": index,
                        "success": False,
                        "error": "缺少cos_key参数"
                    }

                try:
                    # 调用单图处理逻辑
                    result = _process_single_image_internal(
                        cos_key, quality_level, tile_size
                    )

                    return {
                        "index": index,
                        "cos_key": cos_key,
                        **result
                    }

                except Exception as e:
                    logger.error(
                        f"[批处理] 处理图片失败 (index={index}): {e}", exc_info=True
                    )
                    return {
                        "index": index,
                        "cos_key": cos_key,
                        "success": False,
                        "error": "处理异常",
                        "detail": str(e),
                    }

            # 使用线程池并发处理
            with ThreadPoolExecutor(max_workers=concurrency) as executor:
                # 提交所有任务
                futures = {
                    executor.submit(process_one_image, index, img): index
                    for index, img in enumerate(images)
                }

                # 按完成顺序收集结果，缓存到字典
                for future in as_completed(futures):
                    result = future.result()
                    index = result["index"]
                    
                    # 更新统计
                    if result.get("success"):
                        completed += 1
                    else:
                        failed += 1
                    
                    # ✅ 直接按完成顺序返回（无需缓存）
                    yield json.dumps(result, ensure_ascii=False) + "\n"
                    
                    logger.info(
                        f"[批处理] 返回结果: index={index}, 进度: {completed+failed}/{len(images)}, 成功: {completed}, 失败: {failed}"
                    )

            # 最后返回汇总信息
            total_time = time.time() - start_time
            logger.info(
                f"[批处理] 完成！总数: {len(images)}, 成功: {completed}, 失败: {failed}, 并发数: {concurrency}, 总时间: {total_time:.2f}秒"
            )

            yield json.dumps(
                {
                    "summary": {
                        "total": len(images),
                        "completed": completed,
                        "failed": failed,
                        "concurrency": concurrency,
                        "total_time": round(total_time, 2),
                    }
                },
                ensure_ascii=False,
            ) + "\n"

        except Exception as e:
            logger.error(f"[批处理] 批处理失败: {e}", exc_info=True)
            yield json.dumps(
                {"success": False, "error": "批处理失败", "detail": str(e)},
                ensure_ascii=False,
            ) + "\n"

    return Response(generate(), mimetype="application/x-ndjson")


@app.route("/api/v1/enhance", methods=["POST"])
def enhance_image():
    """
    图片增强API - 支持COS URL工作流和多GPU服务器负载均衡
    """
    try:
        logger.info("收到图片增强请求")

        # 获取JSON数据
        if request.is_json:
            request_data = request.get_json()
        else:
            request_data = request.form.to_dict()

        # 检查是否有图片URL（新的COS URL工作流）
        image_url = request_data.get("image_url")
        if not image_url:
            return jsonify({"error": "缺少image_url参数"}), 400

        # 准备转发到后端的请求数据
        data = {"image_url": image_url}

        # 获取其他参数
        if "tile_size" in request_data:
            data["tile_size"] = request_data["tile_size"]
        if "quality_level" in request_data:
            data["quality_level"] = request_data["quality_level"]
        if "session_id" in request_data:
            data["session_id"] = request_data["session_id"]

        # 从请求头获取会话ID
        session_id = request.headers.get("X-Session-ID") or data.get("session_id")

        # 使用config.get_backend_url()自动处理负载均衡
        backend_url = config.get_backend_url()
        if not backend_url:
            logger.error("没有可用的后端服务器")
            return jsonify({"error": "服务暂时不可用，请稍后重试"}), 503

        logger.info(f"使用后端地址: {backend_url}")

        # 转发请求到后端
        full_url = urljoin(backend_url, "/api/v1/enhance")
        logger.info(f"转发请求到: {full_url}")
        logger.info(f"转发数据: {data}")

        response = requests.post(full_url, json=data, timeout=BACKEND_TIMEOUT)

        # 先获取响应数据
        try:
            response_data = response.json()
        except Exception as e:
            logger.error(f"解析后端响应失败: {e}")
            return jsonify({"error": "后端响应格式错误"}), 500

        # 记录任务创建成功并添加任务映射
        if response.status_code == 200:
            task_id = response_data.get("task_id")
            if task_id:
                simple_task_mapping.add_task_mapping(task_id, backend_url)
                logger.info(f"任务创建成功: {task_id} -> {backend_url}")

        # 返回后端响应
        return jsonify(response_data), response.status_code

    except requests.exceptions.Timeout:
        logger.error("请求超时")
        return jsonify({"error": "请求超时，请稍后重试"}), 408
    except requests.exceptions.ConnectionError:
        logger.error("连接后端服务失败")
        return jsonify({"error": "服务暂时不可用"}), 503
    except Exception as e:
        logger.error(f"处理请求时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500


@app.route("/api/v1/status/<task_id>", methods=["GET"])
def get_task_status(task_id):
    """
    查询任务状态API - 支持任务ID到服务器的精确映射
    """
    try:
        logger.info(f"查询任务状态: {task_id}")

        # 首先尝试从任务映射中获取对应的服务器
        backend_url = simple_task_mapping.get_task_server(task_id)

        if not backend_url:
            # 如果没有找到映射，回退到负载均衡
            logger.warning(f"任务 {task_id} 没有找到映射，使用负载均衡")
            backend_url = config.get_backend_url()
            if not backend_url:
                logger.error("没有可用的后端服务器")
                return jsonify({"error": "服务暂时不可用，请稍后重试"}), 503

        logger.info(f"使用后端地址: {backend_url}")

        # 转发请求到后端
        full_url = urljoin(backend_url, f"/api/v1/status/{task_id}")
        logger.info(f"转发请求到: {full_url}")

        response = requests.get(full_url, timeout=30)

        # 注意：不在这里清理映射关系，因为下载请求可能在状态查询之后
        # 映射关系将在下载完成后清理

        # 返回后端响应
        return jsonify(response.json()), response.status_code

    except requests.exceptions.Timeout:
        logger.error("请求超时")
        return jsonify({"error": "请求超时"}), 408
    except requests.exceptions.ConnectionError:
        logger.error("连接后端服务失败")
        return jsonify({"error": "服务暂时不可用"}), 503
    except Exception as e:
        logger.error(f"查询状态时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500


@app.route("/api/v1/download/<task_id>", methods=["GET"])
def download_result(task_id):
    """
    下载处理结果API - 支持任务ID到服务器的精确映射
    """
    try:
        logger.info(f"下载任务结果: {task_id}")

        # 首先尝试从任务映射中获取对应的服务器
        backend_url = simple_task_mapping.get_task_server(task_id)

        if not backend_url:
            # 如果没有找到映射，回退到负载均衡
            logger.warning(f"任务 {task_id} 没有找到映射，使用负载均衡")
            backend_url = config.get_backend_url()
            if not backend_url:
                logger.error("没有可用的后端服务器")
                return jsonify({"error": "服务暂时不可用，请稍后重试"}), 503

        logger.info(f"使用后端地址: {backend_url}")

        # 转发请求到后端
        full_url = urljoin(backend_url, f"/api/v1/download/{task_id}")
        logger.info(f"转发请求到: {full_url}")

        response = requests.get(full_url, timeout=60, stream=True)

        if response.status_code == 200:
            # 下载成功后清理任务映射关系
            simple_task_mapping.remove_task_mapping(task_id)
            logger.info(f"任务 {task_id} 下载完成，清理映射关系")

            # 直接返回文件流
            return send_file(
                response.raw,
                mimetype=response.headers.get(
                    "content-type", "application/octet-stream"
                ),
                as_attachment=True,
                download_name=f"enhanced_{task_id}.jpg",
            )
        else:
            return jsonify(response.json()), response.status_code

    except requests.exceptions.Timeout:
        logger.error("下载超时")
        return jsonify({"error": "下载超时"}), 408
    except requests.exceptions.ConnectionError:
        logger.error("连接后端服务失败")
        return jsonify({"error": "服务暂时不可用"}), 503
    except Exception as e:
        logger.error(f"下载时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500


@app.route("/api/v1/health", methods=["GET"])
def health_check():
    """
    健康检查接口
    """
    try:
        # 检查后端服务是否可用
        backend_url = config.get_backend_url()
        if backend_url:
            full_url = urljoin(backend_url, "/health")
            response = requests.get(full_url, timeout=5)

            return (
                jsonify(
                    {
                        "status": "healthy",
                        "backend_status": "connected",
                        "backend_url": backend_url,
                        "backend_response": response.status_code,
                        "timestamp": time.time(),
                    }
                ),
                200,
            )
        else:
            return (
                jsonify(
                    {
                        "status": "healthy",
                        "backend_status": "no_servers",
                        "backend_url": None,
                        "message": "没有可用的后端服务器",
                        "gateway_status": "running",
                        "timestamp": time.time(),
                    }
                ),
                200,
            )

    except Exception as e:
        # 即使后端不可用，网关本身仍然健康
        return (
            jsonify(
                {
                    "status": "healthy",
                    "backend_status": "disconnected",
                    "backend_url": config.get_backend_url(),
                    "backend_error": str(e),
                    "gateway_status": "running",
                    "timestamp": time.time(),
                }
            ),
            200,
        )


@app.route("/api/v1/system/status", methods=["GET"])
def get_system_status():
    """
    获取HAI优化系统状态
    """
    try:
        # 尝试从HAI优化系统获取状态
        hai_opt_url = "http://127.0.0.1:8080/api/v1/system/status"
        response = requests.get(hai_opt_url, timeout=10)

        if response.status_code == 200:
            return jsonify(response.json()), 200
        else:
            return (
                jsonify(
                    {
                        "success": False,
                        "error": f"HAI优化系统响应错误: {response.status_code}",
                    }
                ),
                500,
            )

    except requests.exceptions.ConnectionError:
        return jsonify({"success": False, "error": "HAI优化系统连接失败"}), 503
    except Exception as e:
        logger.error(f"获取系统状态失败: {str(e)}")
        return jsonify({"success": False, "error": str(e)}), 500


@app.route("/api/v1/info", methods=["GET"])
def api_info():
    """
    API信息接口
    """
    return jsonify(
        {
            "name": "PhotoEnhance API Gateway",
            "version": "1.0.0",
            "description": "为微信小程序提供HTTPS API接口，支持多GPU服务器负载均衡",
            "endpoints": {
                "enhance": "/api/v1/enhance",
                "status": "/api/v1/status/{task_id}",
                "download": "/api/v1/download/{task_id}",
                "health": "/api/v1/health",
                "info": "/api/v1/info",
                "config": "/api/v1/config",
                "wechat_auth": {"openid": "/api/wechat/auth/openid"},
                "wechat_pay": {
                    "create": "/api/wechat/pay/create",
                    "notify": "/api/wechat/pay/notify",
                    "query": "/api/wechat/pay/query/{out_trade_no}",
                    "orders": "/api/wechat/pay/orders/{openid}",
                    "stats": "/api/wechat/pay/stats",
                },
                "webhook": {
                    "register": "/webhook/register",
                    "unregister": "/webhook/unregister",
                    "servers": "/webhook/servers",
                },
            },
            "config_info": config.get_config_info(),
        }
    )


@app.route("/api/v1/config", methods=["GET"])
def get_config():
    """
    获取配置信息接口
    """
    return jsonify(config.get_config_info())


@app.route("/api/v1/config/backend", methods=["POST"])
def update_backend_config():
    """
    更新默认后端服务地址接口
    """
    try:
        data = request.get_json()
        if not data or "backend_url" not in data:
            return jsonify({"error": "缺少backend_url参数"}), 400

        new_url = data["backend_url"]
        success = config.update_backend_url(new_url)

        if success:
            return (
                jsonify(
                    {
                        "message": "默认后端服务地址更新成功",
                        "new_backend_url": new_url,
                        "timestamp": time.time(),
                    }
                ),
                200,
            )
        else:
            return jsonify({"error": "更新失败"}), 500

    except Exception as e:
        logger.error(f"更新后端配置时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500


@app.route("/api/v1/config/multi-backend", methods=["POST"])
def update_multi_backend_config():
    """
    更新多GPU服务器配置接口
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "请求数据为空"}), 400

        success = True
        messages = []

        # 启用/禁用多GPU服务器模式
        if "enabled" in data:
            enabled = bool(data["enabled"])
            if config.enable_multi_backend(enabled):
                status = "启用" if enabled else "禁用"
                messages.append(f"多GPU服务器模式已{status}")
            else:
                success = False
                messages.append("设置多GPU服务器模式失败")

        # 设置回退模式
        if "fallback_to_default" in data:
            fallback = bool(data["fallback_to_default"])
            if config.set_fallback_to_default(fallback):
                status = "启用" if fallback else "禁用"
                messages.append(f"回退到默认配置已{status}")
            else:
                success = False
                messages.append("设置回退模式失败")

        if success:
            return (
                jsonify(
                    {
                        "message": "配置更新成功",
                        "details": messages,
                        "config": config.get_config_info(),
                        "timestamp": time.time(),
                    }
                ),
                200,
            )
        else:
            return jsonify({"error": "部分配置更新失败", "details": messages}), 500

    except Exception as e:
        logger.error(f"更新多GPU服务器配置时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500


# ==================== 微信认证相关API ====================


@app.route("/api/wechat/auth/openid", methods=["POST"])
def get_openid():
    """通过code获取openid"""
    try:
        data = request.get_json()

        if not data or "code" not in data:
            return jsonify({"success": False, "error": "缺少code参数"}), 400

        code = data["code"]
        result = wechat_auth.get_openid(code)

        if result["success"]:
            return jsonify(
                {
                    "success": True,
                    "data": {
                        "openid": result["data"]["openid"],
                        "session_key": result["data"]["session_key"],
                    },
                }
            )
        else:
            return jsonify({"success": False, "error": result["error"]}), 400

    except Exception as e:
        logger.error(f"获取openid失败: {str(e)}")
        return jsonify({"success": False, "error": "服务器内部错误"}), 500


# ==================== 微信支付相关API ====================


@app.route("/api/wechat/pay/create", methods=["POST"])
def create_payment():
    """创建支付订单"""
    try:
        data = request.get_json()

        # 验证必要参数
        required_fields = ["openid", "total_fee", "body"]
        for field in required_fields:
            if field not in data:
                return (
                    jsonify({"success": False, "error": f"缺少必要参数: {field}"}),
                    400,
                )

        openid = data["openid"]
        total_fee = int(data["total_fee"])  # 单位：分
        body = data["body"]
        attach = data.get("attach", "")

        # 验证金额
        if total_fee <= 0 or total_fee > 1000000:  # 最大10000元
            return jsonify({"success": False, "error": "金额无效"}), 400

        # 创建本地订单
        order = order_manager.create_order(openid, total_fee, body, attach)

        # 调用微信支付API创建订单
        result = pay_api.create_order(openid, total_fee, body, attach)

        if result["success"]:
            # 更新本地订单的prepay_id
            order_manager.update_order(
                order["out_trade_no"], prepay_id=result["data"]["prepay_id"]
            )

            return jsonify(
                {
                    "success": True,
                    "data": {
                        "out_trade_no": order["out_trade_no"],
                        "pay_params": result["data"]["pay_params"],
                    },
                }
            )
        else:
            # 创建失败，删除本地订单
            order_manager.mark_order_failed(order["out_trade_no"])
            return jsonify({"success": False, "error": result["error"]}), 500

    except Exception as e:
        logger.error(f"创建支付订单失败: {str(e)}")
        return jsonify({"success": False, "error": "服务器内部错误"}), 500


@app.route("/api/wechat/pay/notify", methods=["POST"])
def payment_notify():
    """支付回调通知"""
    try:
        # 获取回调数据
        xml_data = request.get_data(as_text=True)
        logger.info(f"收到支付回调: {xml_data}")

        # 解析XML数据
        callback_data = WeChatPayUtils.xml_to_dict(xml_data)

        # 验证签名
        sign = callback_data.pop("sign", "")
        if not WeChatPayUtils.verify_sign(callback_data, sign, WeChatPayConfig.API_KEY):
            logger.error("支付回调签名验证失败")
            return WeChatPayUtils.dict_to_xml(
                {"return_code": "FAIL", "return_msg": "签名验证失败"}
            )

        # 检查支付结果
        if (
            callback_data.get("return_code") == "SUCCESS"
            and callback_data.get("result_code") == "SUCCESS"
        ):
            out_trade_no = callback_data.get("out_trade_no")
            transaction_id = callback_data.get("transaction_id")
            time_end = callback_data.get("time_end")

            # 更新订单状态
            if order_manager.mark_order_paid(out_trade_no, transaction_id, time_end):
                logger.info(f"订单支付成功: {out_trade_no}")

                # 这里可以添加业务逻辑，比如：
                # - 发送支付成功通知
                # - 更新用户权益
                # - 记录支付日志

                return WeChatPayUtils.dict_to_xml(
                    {"return_code": "SUCCESS", "return_msg": "OK"}
                )
            else:
                logger.error(f"更新订单状态失败: {out_trade_no}")
                return WeChatPayUtils.dict_to_xml(
                    {"return_code": "FAIL", "return_msg": "订单不存在"}
                )
        else:
            logger.error(f"支付失败: {callback_data}")
            return WeChatPayUtils.dict_to_xml(
                {"return_code": "FAIL", "return_msg": "支付失败"}
            )

    except Exception as e:
        logger.error(f"处理支付回调失败: {str(e)}")
        return WeChatPayUtils.dict_to_xml(
            {"return_code": "FAIL", "return_msg": "处理失败"}
        )


@app.route("/api/wechat/pay/query/<out_trade_no>", methods=["GET"])
def query_payment(out_trade_no):
    """查询支付状态"""
    try:
        # 先查询本地订单
        local_order = order_manager.get_order(out_trade_no)
        if not local_order:
            return jsonify({"success": False, "error": "订单不存在"}), 404

        # 如果本地订单已支付，直接返回
        if local_order["status"] == WeChatPayConfig.ORDER_STATUS_PAID:
            return jsonify(
                {
                    "success": True,
                    "data": {
                        "out_trade_no": out_trade_no,
                        "status": local_order["status"],
                        "transaction_id": local_order["transaction_id"],
                        "time_end": local_order["time_end"],
                    },
                }
            )

        # 查询微信支付状态
        result = pay_api.query_order(out_trade_no)

        if result["success"]:
            trade_state = result["data"]["trade_state"]

            # 根据微信支付状态更新本地订单
            if trade_state == "SUCCESS":
                order_manager.mark_order_paid(
                    out_trade_no,
                    result["data"]["transaction_id"],
                    result["data"]["time_end"],
                )
            elif trade_state in ["CLOSED", "REVOKED", "PAYERROR"]:
                order_manager.mark_order_failed(out_trade_no)

            return jsonify({"success": True, "data": result["data"]})
        else:
            return jsonify({"success": False, "error": result["error"]}), 500

    except Exception as e:
        logger.error(f"查询支付状态失败: {str(e)}")
        return jsonify({"success": False, "error": "服务器内部错误"}), 500


@app.route("/api/wechat/pay/orders/<openid>", methods=["GET"])
def get_user_orders(openid):
    """获取用户订单列表"""
    try:
        orders = order_manager.get_orders_by_openid(openid)

        # 只返回必要信息，不包含敏感数据
        safe_orders = []
        for order in orders:
            safe_orders.append(
                {
                    "out_trade_no": order["out_trade_no"],
                    "total_fee": order["total_fee"],
                    "body": order["body"],
                    "status": order["status"],
                    "create_time": order["create_time"],
                    "time_end": order["time_end"],
                }
            )

        return jsonify({"success": True, "data": safe_orders})

    except Exception as e:
        logger.error(f"获取用户订单失败: {str(e)}")
        return jsonify({"success": False, "error": "服务器内部错误"}), 500


@app.route("/api/wechat/pay/stats", methods=["GET"])
def get_payment_stats():
    """获取支付统计信息"""
    try:
        stats = order_manager.get_order_stats()
        return jsonify({"success": True, "data": stats})

    except Exception as e:
        logger.error(f"获取支付统计失败: {str(e)}")
        return jsonify({"success": False, "error": "服务器内部错误"}), 500


@app.errorhandler(404)
def not_found(error):
    return jsonify({"error": "API接口不存在"}), 404


@app.errorhandler(405)
def method_not_allowed(error):
    return jsonify({"error": "HTTP方法不允许"}), 405


@app.errorhandler(500)
def internal_error(error):
    return jsonify({"error": "服务器内部错误"}), 500


@app.route("/api/v1/sessions/cancel", methods=["POST"])
def cancel_session_tasks():
    """
    取消会话的所有任务
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "请求数据为空"}), 400

        session_id = data.get("session_id")
        if not session_id:
            return jsonify({"error": "缺少会话ID"}), 400

        # 转发请求到HAI优化系统
        backend_url = config.get_backend_url()
        if not backend_url:
            logger.error("没有可用的后端服务器")
            return jsonify({"error": "服务暂时不可用，请稍后重试"}), 503

        # 检查是否是HAI优化系统
        if "hai-optimization" in backend_url or "localhost:8080" in backend_url:
            # 直接转发到HAI优化系统
            full_url = urljoin(backend_url, "/api/v1/sessions/cancel")
            response = requests.post(full_url, json=data, timeout=30)
            return jsonify(response.json()), response.status_code
        else:
            # 对于GPU服务器，暂时不支持会话取消
            return jsonify({"error": "当前后端不支持会话取消功能"}), 501

    except requests.exceptions.Timeout:
        logger.error("请求超时")
        return jsonify({"error": "请求超时"}), 408
    except requests.exceptions.ConnectionError:
        logger.error("连接后端服务失败")
        return jsonify({"error": "服务暂时不可用"}), 503
    except Exception as e:
        logger.error(f"取消会话任务时出错: {str(e)}")
        return jsonify({"error": "服务器内部错误"}), 500




# ============================================
# 统计和监控接口
# ============================================


# ============================================
# 统计和监控接口
# ============================================

@app.route('/stats', methods=['GET'])
def get_stats():
    """获取API Gateway统计信息（JSON格式）"""
    try:
        stats = request_stats.get_stats()
        
        # 添加GPU服务器信息
        try:
            gpu_servers = backend_manager.get_all_servers()
            stats['gpu_count'] = len(gpu_servers)
            stats['gpu_servers'] = [
                {
                    'url': server.get('url', 'N/A'),
                    'health': 'healthy' if server.get('is_healthy') else 'unhealthy',
                    'last_check': server.get('last_check_time', 'N/A')
                }
                for server in gpu_servers
            ]
        except Exception as e:
            logger.error(f"获取GPU服务器信息失败: {e}")
            stats['gpu_count'] = 0
            stats['gpu_servers'] = []
        
        return jsonify(stats)
    except Exception as e:
        logger.error(f"/stats接口错误: {e}", exc_info=True)
        return jsonify({"error": str(e)}), 500


@app.route('/metrics', methods=['GET'])
def get_metrics():
    """获取Prometheus格式的监控指标"""
    try:
        metrics = request_stats.get_prometheus_metrics()
        
        # 添加GPU数量指标
        try:
            gpu_count = len(backend_manager.get_all_servers())
        except Exception:
            gpu_count = 0
        
        metrics += f"\n# HELP gpu_servers_healthy Number of healthy GPU servers\n"
        metrics += f"# TYPE gpu_servers_healthy gauge\n"
        metrics += f"gpu_servers_healthy {gpu_count}\n"
        
        from flask import Response
        return Response(metrics, mimetype='text/plain; charset=utf-8')
    except Exception as e:
        logger.error(f"/metrics接口错误: {e}", exc_info=True)
        return jsonify({"error": str(e)}), 500


@app.route('/api/v1/server-status', methods=['GET'])
def get_server_status():
    """获取服务器简版状态接口"""
    try:
        # 获取请求统计信息
        stats = request_stats.get_stats()
        queue_length = stats.get('active_requests', 0)
        
        # 获取健康服务器数量
        servers = backend_manager.get_all_servers()
        healthy_servers = [server for server in servers if server.get('is_healthy')]
        current_gpus = len(healthy_servers)
        
        # 根据队列长度判断服务器状态
        if queue_length < 10:
            server_status = "normal"
            status_color = "green"
        elif queue_length <= 30:
            server_status = "busy"
            status_color = "yellow"
        else:
            server_status = "congested"
            status_color = "red"
        
        # 计算预计等待时间
        if current_gpus > 0:
            estimated_wait_seconds = int(queue_length / current_gpus * 10)
        else:
            estimated_wait_seconds = 0
        
        # 生成友好的等待时间文本
        if estimated_wait_seconds == 0:
            estimated_wait_text = "无需等待"
        elif estimated_wait_seconds < 10:
            estimated_wait_text = "约 10 秒以内"
        elif estimated_wait_seconds < 30:
            estimated_wait_text = "约 10-30 秒"
        elif estimated_wait_seconds < 60:
            estimated_wait_text = "约 30-60 秒"
        else:
            minutes = estimated_wait_seconds // 60
            estimated_wait_text = f"约 {minutes} 分钟"
        
        # 构造响应数据
        response_data = {
            "server_status": server_status,
            "status_color": status_color,
            "queue_length": queue_length,
            "estimated_wait_seconds": estimated_wait_seconds,
            "estimated_wait_text": estimated_wait_text,
            "current_gpus": current_gpus,
            "timestamp": int(time.time() * 1000)
        }
        
        return jsonify({
            "success": True,
            "data": response_data
        })
        
    except Exception as e:
        logger.error(f"获取服务器状态失败: {str(e)}")
        return jsonify({
            "success": False,
            "error": str(e)
        }), 500


if __name__ == "__main__":
    logger.info("启动API网关服务...")
    logger.info(
        f"多GPU服务器模式: {'启用' if config.is_multi_backend_enabled() else '禁用'}"
    )
    logger.info("使用HTTPS协议，端口443")

    # 生产环境使用Gunicorn，这里仅用于开发测试
    logger.info("API网关服务配置完成")
    logger.info("生产环境请使用: gunicorn -w 2 -b 127.0.0.1:1000 app:app")

    # 开发环境测试端口
    app.run(host="127.0.0.1", port=1000, debug=False)
